package com.tfswx.fljdmxyy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.newbie.core.exception.BusinessException;
import com.newbie.core.security.util.UserManager;
import com.tfswx.fljdmxyy.constant.SystemConstant;
import com.tfswx.fljdmxyy.dao.QxXtGnflMapper;
import com.tfswx.fljdmxyy.dao.ZzjgXtDwMapper;
import com.tfswx.fljdmxyy.dao.ZzjgXtJsMapper;
import com.tfswx.fljdmxyy.dao.ZzjgXtRyMapper;
import com.tfswx.fljdmxyy.dto.rygl.*;
import com.tfswx.fljdmxyy.enums.BusinessCodeEnum;
import com.tfswx.fljdmxyy.model.ZzjgXtDw;
import com.tfswx.fljdmxyy.model.ZzjgXtJs;
import com.tfswx.fljdmxyy.model.ZzjgXtRy;
import com.tfswx.fljdmxyy.query.rygl.*;
import com.tfswx.fljdmxyy.service.RyglService;
import com.tfswx.fljdmxyy.utils.ConverterUtils;
import com.tfswx.fljdmxyy.utils.UuidUtils;
import com.tfswx.newbie.boot.starter.page.PageHelper;
import com.tfswx.newbie.boot.starter.page.PageParam;
import com.tfswx.newbie.boot.starter.page.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

/**
 * 人员管理实现类
 *
 * @author 唐晓宇
 * @date 2022/11/11
 */
@Slf4j
@Service
public class RyglServiceImpl implements RyglService {
    @Resource
    private ZzjgXtDwMapper zzjgXtDwMapper;

    @Resource
    private ZzjgXtJsMapper zzjgXtJsMapper;

    @Resource
    private ZzjgXtRyMapper zzjgXtRyMapper;

    @Resource
    private QxXtGnflMapper gnflMapper;

    @Value("${tyyw.url}")
    private String tyywUrl;

    @Value("${intPwd}")
    private String intPwd;

    @Override
    public LoginOutputDTO login(LoginInputDTO dto) {
        // 1.查询人员信息
        ZzjgXtRy ryxx = ConverterUtils.convert(dto, ZzjgXtRy.class);
        List<ZzjgXtRy> ryList = zzjgXtRyMapper.queryZzjgXtRy(ryxx);
        if (CollectionUtil.isEmpty(ryList)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "账号或密码错误");
        }

        // 2.处理登录
        return handleLogin(ryList);
    }

    @Override
    public LoginOutputDTO dsfLogin(DsfLoginInputDTO dto) {
        Assert.notBlank(dto.getDwbm());
        Assert.notBlank(dto.getRybm());

        // 1.获取人员信息
        ZzjgXtRy ryxx = ConverterUtils.convert(dto, ZzjgXtRy.class);
        List<ZzjgXtRy> rybmList = zzjgXtRyMapper.queryZzjgXtRy(ryxx);
        if (CollectionUtil.isEmpty(rybmList)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "第三方登录失败");
        }

        // 2.处理登录
        return handleLogin(rybmList);
    }

    @Override
    public LoginOutputDTO unlockLogin(UnlockLoginInputDTO dto) {
        Assert.notBlank(dto.getDwbm());
        Assert.notBlank(dto.getRybm());
        Assert.notBlank(dto.getDlmm());

        // 1.获取人员信息
        ZzjgXtRy ryxx = ConverterUtils.convert(dto, ZzjgXtRy.class);
        List<ZzjgXtRy> ryList = zzjgXtRyMapper.queryZzjgXtRy(ryxx);
        if (CollectionUtil.isEmpty(ryList)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "账号或密码错误");
        }

        // 2.处理登录
        return handleLogin(ryList);
    }

    private LoginOutputDTO handleLogin(List<ZzjgXtRy> ryList) {
        ZzjgXtRy zzjgXtRy = ryList.stream().findFirst().orElse(null);
        // 1.查询人员对应角色的权限文件编号
        ZzjgXtJs jsxx = new ZzjgXtJs();
        jsxx.setJsbm(zzjgXtRy.getJsbm());
        jsxx = zzjgXtJsMapper.getZzjgXtJs(jsxx);
        if (ObjectUtil.isNull(jsxx)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "获取角色功能权限文件编号失败，角色编码："
                    + zzjgXtRy.getJsbm());
        }

        // 2.获取token
        RyxxOutputDTO ryxxOutputDTO = ConverterUtils.convert(zzjgXtRy, RyxxOutputDTO.class);
        UserManager.login(ryxxOutputDTO.getRybm());
        ryxxOutputDTO.setGnbm(jsxx.getGnbm());

        // 3.缓存用户基本信息
        UserManager.setContext(SystemConstant.LOGIN_CONTEXT_KEY, ryxxOutputDTO);

        // 4.返回数据
        LoginOutputDTO outInputDTO = new LoginOutputDTO();
        outInputDTO.setTokenInfo(UserManager.getTokenInfo());
        outInputDTO.setUser(ryxxOutputDTO);
        return outInputDTO;
    }

    @Override
    public RyxxAddOutputDTO addRyxx(RyxxAddInputDTO dto) {
        ZzjgXtRy ryxx = ConverterUtils.convert(dto, ZzjgXtRy.class);

        // 1.校验人员信息
        checkRybm(ryxx);
        Date now = new Date();
        ryxx.setRybm(UuidUtils.uuid32());
        ryxx.setCjsj(now);
        ryxx.setZhxgsj(now);
        ryxx.setSfsc(SystemConstant.N);
        ryxx.setDlmm(intPwd);

        // 2.保存人员信息
        Integer result = zzjgXtRyMapper.insertZzjgXtRy(ryxx);
        if (result <= 0) {
            throw new BusinessException(BusinessCodeEnum.TJSJSB);
        }
        return ConverterUtils.convert(ryxx, RyxxAddOutputDTO.class);
    }

    @Override
    public RyxxUpdateOutputDTO updateRyxx(RyxxUpdateInputDTO dto) {
        ZzjgXtRy ryxx = ConverterUtils.convert(dto, ZzjgXtRy.class);
        // 1.校验人员信息
        checkRybm(ryxx);
        ryxx.setZhxgsj(new Date());

        // 2.保存人员信息
        Integer result = zzjgXtRyMapper.updateZzjgXtRy(ryxx);
        if (result <= 0) {
            throw new BusinessException(BusinessCodeEnum.XGSJSB);
        }
        return ConverterUtils.convert(ryxx, RyxxUpdateOutputDTO.class);
    }

    private void checkRybm(ZzjgXtRy rybm) {
        // 1.验证登录名是否重复
        List<ZzjgXtRy> ryList = zzjgXtRyMapper.queryByDlbm(rybm);
        if (CollectionUtil.isNotEmpty(ryList)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "登录别名已存在：" + rybm.getDlbm());
        }

        // 2.验证单位是否存在
        ZzjgXtDw dwxx = new ZzjgXtDw();
        dwxx.setDwbm(rybm.getDwbm());
        dwxx = zzjgXtDwMapper.getZzjgXtDw(dwxx);
        if (ObjectUtil.isNull(dwxx)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "单位不存在，单位编码：" + rybm.getDwbm());
        }

        // 3.验证角色是否存在
        ZzjgXtJs jsxx = new ZzjgXtJs();
        jsxx.setJsbm(rybm.getJsbm());
        jsxx = zzjgXtJsMapper.getZzjgXtJs(jsxx);
        if (ObjectUtil.isNull(jsxx)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB.getCode(), "角色不存在，角色编码：" + rybm.getJsbm());
        }
    }

    @Override
    public void logout() {
        UserManager.logout();
    }

    @Override
    public RyxxDeleteOutputDTO deleteRyxx(RyxxDeleteInputDTO dto) {
        ZzjgXtRy ryxx = ConverterUtils.convert(dto, ZzjgXtRy.class);
        ryxx.setZhxgsj(new Date());
        Integer result = zzjgXtRyMapper.deleteZzjgXtRy(ryxx);
        if (result <= 0) {
            throw new BusinessException(BusinessCodeEnum.SCSJSB);
        }
        return ConverterUtils.convert(ryxx, RyxxDeleteOutputDTO.class);
    }


    @Override
    public List<RyxxQueryResult> queryRylb(RyxxQueryParam param) {
        ZzjgXtRy ryxx = ConverterUtils.convert(param, ZzjgXtRy.class);
        RyxxOutputDTO ryxxOutputDTO = getUserInfo();
        Assert.notNull(ryxxOutputDTO, "获取登录信息失败");
        ryxx.setDwbm(ryxxOutputDTO.getDwbm());
        List<ZzjgXtRy> ryList = zzjgXtRyMapper.queryZzjgXtRy(ryxx);
        return ConverterUtils.convertList(ryList, RyxxQueryResult.class);
    }

    @Override
    public PageResult<RyxxQueryResult> queryRyxx(PageParam<RyxxQueryParam> param) {
        RyxxOutputDTO ryxxOutputDTO = getUserInfo();
        Assert.notNull(ryxxOutputDTO, "获取登录信息失败");
        RyxxQueryParam filter = param.getFilter();
        filter.setDwbm(ryxxOutputDTO.getDwbm());
        return PageHelper.doSelectPage(param, () -> zzjgXtRyMapper.queryRyxx(filter));

    }

    @Override
    public LoginOutputDTO heartBeat() {
        RyxxOutputDTO ryxxOutputDTO = getUserInfo();
        UserManager.setContext(SystemConstant.LOGIN_CONTEXT_KEY, ryxxOutputDTO);
        LoginOutputDTO loginOut = new LoginOutputDTO();
        loginOut.setUser(ryxxOutputDTO);
        loginOut.setTokenInfo(UserManager.getTokenInfo());
        return loginOut;
    }

    @Override
    public List<TyywryQueryResult> queryTyywry(TyywryQueryParam param) {
        JSONArray array = new JSONArray();
        // 1.调用统一业务查询人员列表
        String post = HttpRequest.post(tyywUrl + SystemConstant.FIND_USER_LIST)
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .timeout(-1).body(JSONUtil.toJsonStr(param)).execute().body();

        // 2.如果返回为空则抛错
        if (StrUtil.isBlank(post)) {
            throw new BusinessException(BusinessCodeEnum.HQSJSB);
        }

        // 3.解析为JSON对象
        JSONObject jsonObject = JSON.parseObject(post);
        if (jsonObject.getBoolean("success")) {
            array = (JSONArray) jsonObject.get("data");
        } else {
            throw new BusinessException(BusinessCodeEnum.HQSJSB);
        }

        // 4.数据转化并返回
        return array.toJavaList(TyywryQueryResult.class);
    }

    @Override
    public RyxxOutputDTO getUserInfo() {
        return UserManager.getContext(SystemConstant.LOGIN_CONTEXT_KEY);
    }


    @Override
    public List<RygnQueryResult> queryRygn(RygnQueryParam param) {
        // 1.获取用户角色信息
        ZzjgXtRy ryInput = ConverterUtils.convert(param, ZzjgXtRy.class);
        ZzjgXtRy ryxx = zzjgXtRyMapper.getZzjgXtRy(ryInput);
        if (ObjectUtil.isNull(ryxx)) {
            throw new BusinessException(BusinessCodeEnum.CXSB.getCode(), "人员信息不存在");
        }
        ZzjgXtJs jsxx = new ZzjgXtJs();
        jsxx.setJsbm(ryxx.getJsbm());
        jsxx = zzjgXtJsMapper.getZzjgXtJs(jsxx);
        List<RygnQueryResult> result = new ArrayList<>();
        // 2.获取功能树
        if (ObjectUtil.isNotNull(jsxx)) {
            if (StrUtil.isNotBlank(jsxx.getGnbm())) {
                // 2.1 获取所有功能编码
                List<String> gnbmList = Arrays.asList(jsxx.getGnbm().split(","));
                if (CollectionUtil.isNotEmpty(gnbmList)) {
                    // 2.2 查询所有功能定义
                    result = gnflMapper.queryGnByRybm(gnbmList);
                }
            }
            return result;
        }
        throw new BusinessException(BusinessCodeEnum.CXSB.getCode(), "未进行角色分配");
    }

    @Override
    public Boolean updateDlmm(DlmmUpdateInputDTO dto) {
        if (dto.getXkl().equals(dto.getYkl())) {
            throw new BusinessException(BusinessCodeEnum.XGSJSB.getCode(), "原密码和新密码不能一样");
        }
        ZzjgXtRy ryxx = new ZzjgXtRy();
        ryxx.setRybm(dto.getRybm());
        ryxx.setDlmm(dto.getYkl());
        ZzjgXtRy result = zzjgXtRyMapper.getZzjgXtRy(ryxx);
        if (ObjectUtil.isEmpty(result)) {
            throw new BusinessException(BusinessCodeEnum.XGSJSB.getCode(), "原始密码错误!");
        }

        result.setDlmm(dto.getXkl());
        result.setZhxgsj(new Date());
        int res = zzjgXtRyMapper.updateZzjgXtRy(result);
        if (res < 1) {
            throw new BusinessException(BusinessCodeEnum.XGSB);
        }
        return true;
    }

    @Override
    public Boolean resetDlmm(DlmmResetInputDTO dto) {
        ZzjgXtRy ryxx = new ZzjgXtRy();
        ryxx.setRybm(dto.getRybm());
        ZzjgXtRy result = zzjgXtRyMapper.getZzjgXtRy(ryxx);
        if (ObjectUtil.isEmpty(result)) {
            throw new BusinessException(BusinessCodeEnum.XGSJSB.getCode(), "重置密码错误!");
        }
        result.setDlmm(intPwd);
        result.setZhxgsj(new Date());
        int res = zzjgXtRyMapper.updateZzjgXtRy(result);
        if (res < 1) {
            throw new BusinessException(BusinessCodeEnum.XGSB);
        }
        return true;
    }

    @Override
    public RylbAddOutputDTO addRylb(RylbBatchAddInputDTO inputDTOS) {
        RylbAddOutputDTO outputDTO = new RylbAddOutputDTO();
        List<RylbAddInputDTO> inputDTOList = inputDTOS.getRylb();
        // 1.通过人员编码去重
        inputDTOList = inputDTOList.stream().collect(collectingAndThen(
                toCollection(() -> new TreeSet<>(Comparator.comparing(RylbAddInputDTO::getRybm))), ArrayList::new));

        // 2.查询相关信息（单位名称、人员登录别名）
        TyywryQueryParam tyywryQueryParam = new TyywryQueryParam();
        String dw = inputDTOList.get(0).getDwbm();
        tyywryQueryParam.setDwbm(dw);
        Map<String, String> dlbmMap = new HashMap<>();
        queryTyywry(tyywryQueryParam).forEach(item -> dlbmMap.put(item.getRybm(), item.getDlbm()));

        AtomicInteger cgs = new AtomicInteger();
        AtomicInteger sbs = new AtomicInteger();
        List<String> sbRymc = new ArrayList<>();
        inputDTOList.stream().forEach(inputDTO -> {
            ZzjgXtRy ryxx = ConverterUtils.convert(inputDTO, ZzjgXtRy.class);
            try {

                // 3.初始化信息
                Date now = new Date();
                ryxx.setZhxgsj(now);
                ryxx.setDlmm(intPwd);
                // 3.1如果未传入登录别名，则从统一业务人员登录别名获取
                if (StrUtil.isBlank(ryxx.getDlbm())) {
                    String dlbm = dlbmMap.get(ryxx.getRybm());
                    if (StrUtil.isBlank(dlbm)) {
                        throw new BusinessException("获取登录别名失败！");
                    }
                    ryxx.setDlbm(dlbm);
                }

                // 4.校验人员信息
                checkRybm(ryxx);

                // 5.存在该人员编码则修改,不存在则新增
                ZzjgXtRy ry = zzjgXtRyMapper.getRy(ryxx);
                int result = 0;
                if (ObjectUtil.isNotNull(ry)) {
                    result = zzjgXtRyMapper.updateZzjgXtRy(ryxx);
                } else {
                    ryxx.setCjsj(now);
                    ryxx.setSfsc(SystemConstant.N);
                    result = zzjgXtRyMapper.insertZzjgXtRy(ryxx);

                }

                // 6.保存失败时记录日志
                if (result <= 0) {
                    log.error("{}保存失败", ryxx.getRybm());
                    throw new BusinessException(BusinessCodeEnum.TJSJSB);
                }
                cgs.getAndIncrement();
            } catch (Exception e) {
                log.error(e.getMessage());
                sbRymc.add(ryxx.getRymc());
                sbs.getAndIncrement();
                return;
            }
        });
        outputDTO.setCgs(cgs.get());
        outputDTO.setSbs(sbs.get());
        if (CollectionUtil.isNotEmpty(sbRymc)) {
            String sbRymcjh = StringUtils.join(sbRymc, "，");
            outputDTO.setErrorMessage(sbRymcjh + " 保存失败！");
        }
        return outputDTO;
    }
}
